#include "libRaid1.h"

// VARIABLES GLOBALES
uint32_t cantPPD;
uint64_t sectoresMaestros;
nodoLista *ppd;

// SEMÁFOROS
pthread_mutex_t semaforoCantPPD = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t semaforoSectoresMaestros = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t semaforoPPD = PTHREAD_MUTEX_INITIALIZER;

uint32_t main(void) {

	// LEER ARCHIVO DE CONFIGURACIÓN
	char *puerto;
	uint8_t flagConsola;

	parsearConfiguracion("/home/utn_so/Escritorio/configRaid.txt", &puerto, &flagConsola);

	// CABEZAL DE LA CONSOLA
	if (flagConsola == 1) {
		printf("============================================================\n");
		printf("                            _____\n");
		printf("                     _..--''     ``--.._\n");
		printf("                    |                   |\n");
		printf("                    |                   |\n");
		printf("                    |                   |\n");
		printf("                    |                   |\n");
		printf("                    |        .-.        |\n");
		printf("                    |   .'\\  | |  /`,   |\n");
		printf("                    |    `.\\ : ; /,'    |\n");
		printf("                    |   ___`' v `'___   |\n");
		printf("                    | .'   `.   .'   `. |\n");
		printf("                    | |     |   |     | |\n");
		printf("                    | |     |   |     | |\n");
		printf("                    | `.___,',^.`.___,' |\n");
		printf("                    |       /   \\       |\n");
		printf("                    |       `---'       |\n");
		printf("                    |   _____________   |\n");
		printf("                    |  / |    |    | \\  |\n");
		printf("                    |  :-|----|----|-:  |\n");
		printf("                    |  \\_|____|____|_/  |\n");
		printf("                    |                   |\n");
		printf("                    `-..._         _...-'\n");
		printf("                          `-------'\n");
		printf("              ______ _       ___ ___  ________ \n");
		printf("              |  ___| |     / _ \\|  \\/  |  ___|\n");
		printf("              | |_  | |    / /_\\ \\ .  . | |__  \n");
		printf("              |  _| | |    |  _  | |\\/| |  __| \n");
		printf("              | |   | |____| | | | |  | | |___ \n");
		printf("              \\_|   \\_____/\\_| |_|_|  |_|____/ \n");
		printf("\n");
		printf("============================================================\n");
		printf("                        PROCESO RAID                        \n");
		printf("============================================================\n");
		printf("DATOS DE CONFIGURACION\n");
		printf("------------------------------------------------------------\n");
		printf("Puerto: %s, Flag: %d\n", puerto, flagConsola);
		printf("------------------------------------------------------------\n");
	}

	// INICIALIZACIÓN DE THREADS
	pthread_t threadCliente[MAX_THREADS];
	variablesCliente variablesCliente[MAX_THREADS];

	// INICIALIZACIÓN DE CONTADORES
	uint32_t numeroCliente = 0;

	// INICIALIZACIÓN DE VARIABLES GLOBALES
	cantPPD = 0;
	sectoresMaestros = 0;
	ppd = (nodoLista*) malloc(sizeof(nodoLista));
	ppd = NULL;

	// INICIALIZACIÓN DE SOCKET
	uint32_t addrlen = sizeof(struct sockaddr_in);
	uint32_t descriptor = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in *local_address = malloc(sizeof(struct sockaddr_in));
	struct sockaddr_in *remote_address = malloc(sizeof(struct sockaddr_in));

	{
		local_address->sin_family = AF_INET;
		local_address->sin_addr.s_addr = INADDR_ANY;
		local_address->sin_port = htons(atoi(puerto));

		if (bind(descriptor, (struct sockaddr *) local_address, sizeof(struct sockaddr_in)) == -1) {
			if (flagConsola == 1) {
				printf("Error en el bind() \n");
			}
			close(descriptor);
			return -1;
		} else {
			if (flagConsola == 1) {
				printf("Exito en el bind() \n");
			}
		}
	}

	if (listen(descriptor, MAX_CONNECTIONS) == -1) {
		if (flagConsola == 1) {
			printf("Error en el listen() \n");
		}
		close(descriptor);
		return -1;
	} else {
		if (flagConsola == 1) {
			printf("Exito en el listen() \n");
			printf("A la escucha... \n");
		}
	}

	while (1) {
		int64_t cliente = accept(descriptor, (struct sockaddr *) remote_address, (void *) &addrlen);
		if (cliente > 0) {
			variablesCliente[numeroCliente].flagConsola = flagConsola;
			variablesCliente[numeroCliente].numeroCliente = numeroCliente;
			variablesCliente[numeroCliente].fileDescriptor = cliente;
			variablesCliente[numeroCliente].nodoSincronizacion = (nodoLista*) malloc(sizeof(nodoLista));
			variablesCliente[numeroCliente].nodoSincronizacion = NULL;
			variablesCliente[numeroCliente].nodoLectura = (nodoLista*) malloc(sizeof(nodoLista));
			variablesCliente[numeroCliente].nodoLectura = NULL;
			variablesCliente[numeroCliente].bufCrudo = (char*) malloc(sizeof(char) * MAX_BUFFER);
			variablesCliente[numeroCliente].bufTiempo = (char*) malloc(sizeof(char) * BUFFER_TIEMPO);
			variablesCliente[numeroCliente].errorYaExiste = (char*) malloc(sizeof(char) * 16);
			variablesCliente[numeroCliente].errorCeroPlanificadores = (char*) malloc(sizeof(char) * 14);
			variablesCliente[numeroCliente].errorSectoresInsuficientes = (char*) malloc(sizeof(char) * 15);
			variablesCliente[numeroCliente].registroNuevo.id = (char*) malloc(sizeof(char) * MAX_BUFFER);
			variablesCliente[numeroCliente].paqueteLectura.payLoad = (uint64_t*) malloc(sizeof(char) * 8);
			variablesCliente[numeroCliente].buferLectura = (char*) malloc(sizeof(char) * MAX_BUFFER);
			variablesCliente[numeroCliente].paqueteSincroDescerealizado = (char*) malloc(sizeof(char) * MAX_BUFFER);

			if (pthread_create(&threadCliente[numeroCliente], NULL, (void*) &atenderCliente, (void*) &variablesCliente[numeroCliente]) == 0) {
				if (flagConsola == 1) {
					printf("------------------------------------------------------------\n");
					printf("Atendiendo cliente en el thread %i \n", numeroCliente);
					printf("------------------------------------------------------------\n");
				}
				numeroCliente++;
			} else {
				if (flagConsola == 1) {
					printf("------------------------------------------------------------\n");
					printf("Error en la creacion del thread %i \n", numeroCliente);
					printf("------------------------------------------------------------\n");
				}
			}
		}
		pthread_mutex_lock(&semaforoCantPPD);
		cantPPD = contarNodos();
		pthread_mutex_unlock(&semaforoCantPPD);
	}
	return 0;
}
